//-----------------------------------------------------------------------------
//
// @file	FileOps.cpp
// @brief	FileOps file
// @author	Vinod Melapudi
// @date	20Feb2010
//
//-----------------------------------------------------------------------------

#include <windows.h>
#include <stdio.h>
#include "FileOps.h"
#include "Utils.h"
#include "Mesh.h"

#include <png.h>
//
// @brief	Read a file into a string
//			Mallocs char*, this should be free later
//
char* ReadFileToString( const char* fileName )
{
	// Read file
	FILE * file = fopen( fileName, "rb" );
	if ( file == NULL ) 
	{
		fprintf( stderr, "Can't open file '%s' for reading\n", fileName );
		return NULL;
	}

	// File length
	fseek( file, 0, SEEK_END );
	long len = ftell( file );

	char* str = (char*) malloc(len * sizeof(char));
	if ( str == NULL )
	{
		fprintf(stderr, "Can't allocate space for '%s'\n", fileName );
		return NULL;
	}

	fseek( file, 0, SEEK_SET );
	long read = fread( str, sizeof(char), len, file );
	fclose( file );

	str[read-1] = '\0';
 	return str;
}

//
// @brief	Read PLY file into mesh
//
bool ReadPLYFile( const char* plyFile, Mesh& mesh )
{
	// Read file
	FILE* file = fopen( plyFile, "r" );
	if ( file == NULL ) 
	{
		fprintf( stderr, "Can't open file '%s' for reading\n", plyFile );
		return false;
	}

	char line[1024];
	fgets( line, sizeof(line), file );
	if ( strcmp(line, "ply\n") )
	{
		fprintf( stderr, "File '%s' is not of ply type\n", plyFile );
		fclose( file );
		return false;
	}

	enum State
	{
		READ_HEADER,
		READ_VERTICES,
		READ_FACES,
		READ_NONE
	};
	State state = READ_HEADER;

	int vertices_read = 0;
	int num_vertices = 0;
	int faces_read = 0;
	int num_faces = 0;

	// Read line by line
	while( fgets( line, sizeof(line), file ) != NULL )
	{
		switch( state )
		{
		case READ_HEADER:
			{
				vector<std::string> tokens = GetStringTokens( line, " " );

				// Check ascii
				if ( strcmp(tokens[0].c_str(), "format")==0 && strcmp(tokens[1].c_str(), "ascii") )
				{
					fprintf( stderr, "File '%s' is not ascii\n", plyFile );
					fclose( file );
					return false;
				}

				// Get num vertices
				if ( strcmp(tokens[0].c_str(), "element")==0 && strcmp(tokens[1].c_str(), "vertex")==0 )
				{
					sscanf( tokens[2].c_str(), "%d", &num_vertices );
				}

				// Get num faces
				if ( strcmp(tokens[0].c_str(), "element")==0 && strcmp(tokens[1].c_str(), "face")==0 )
				{
					sscanf( tokens[2].c_str(), "%d", &num_faces );
				}

				// End header
				if ( strcmp(line, "end_header\n") == 0 )
				{
					if ( num_vertices == 0 || num_faces == 0 )
					{
						fprintf( stderr, "File '%s' doesnt have vertices or faces\n", plyFile );
						fclose( file );
						return false;
					}
					mesh.m_vtx_positions.reserve( num_vertices );
					mesh.m_face_vtx_indices.reserve( num_faces*3 );
					state = READ_VERTICES;
				}
			}
			break;
		case READ_VERTICES:
			{
				// Get vertices
				float x, y, z;
				float confidence, intensity;
				sscanf( line, "%f %f %f %f %f\n", &x, &y, &z, &confidence, &intensity );
				vertices_read++;
				mesh.m_vtx_positions.push_back( Vector3(x,y,z) );

				// Check if reading vertices are done
				if ( vertices_read >= num_vertices )
					state = READ_FACES;
			}
			break;
		case READ_FACES:
			{
				int num_vertices;
				int v1, v2, v3;
				sscanf( line, "%d %d %d %d\n", &num_vertices, &v1, &v2, &v3 );
				faces_read++;

				mesh.m_face_vtx_indices.push_back( v1 );
				mesh.m_face_vtx_indices.push_back( v2 );
				mesh.m_face_vtx_indices.push_back( v3 );

				// Check if reading faces are done
				if ( faces_read >= num_faces )
					state = READ_NONE;
			}
			break;
		};
	}

	fclose( file );
	return true;
}
